# coding=utf-8
# -*- coding: UTF-8 -*-
#
# This file is part of the kernelstudio package.
#
# (c) 2014-2025 zlin <admin@kernelstudio.com>
#
# For the full copyright and license information, please view the LICENSE file
# that was distributed with this source code.

import dataclasses
import datetime
import decimal
import typing as t
import uuid
from types import NoneType


class JsonSerializable(object):

    def serialize(self) -> t.Optional[dict]:
        pass

    def deserialize(self, data: dict) -> t.Optional[object]:
        return None


def serialize(o: t.Any) -> t.Any:
    def serialize_dict(d: t.Any) -> t.Any:
        dict_value = {}
        for e in d:
            dict_value[e] = serialize(d[e])
        return dict_value

    if isinstance(o, JsonSerializable):
        dv = o.serialize()
        if isinstance(dv, dict):
            return serialize_dict(dv)

    if isinstance(o, dict):
        return serialize_dict(o)

    if isinstance(o, list):
        return [serialize(o) for o in o]

    if isinstance(o, datetime.date) or isinstance(o, datetime.datetime):
        return o.strftime("%Y-%m-%d %H:%M:%S")

    if isinstance(o, uuid.UUID):
        return str(o)

    if isinstance(o, NoneType):
        return None

    if isinstance(o, bytes):
        return str(o, encoding='utf-8')
    if isinstance(o, bool):
        return bool(o)
    if isinstance(o, int):
        return int(o)
    if isinstance(o, float):
        return float(o)
    if isinstance(o, str) or isinstance(o, dict):
        return o

    if isinstance(o, (decimal.Decimal, uuid.UUID)):
        return str(o)

    if dataclasses and dataclasses.is_dataclass(o):
        return dataclasses.asdict(o)  # type: ignore[arg-type]

    if hasattr(o, "__html__"):
        return str(o.__html__())

    raise TypeError(f"Object of type {type(o).__name__} is not JSON serializable")
